// @ts-ignore
import styles from './index.less'
import React, {useContext, useEffect, useMemo, useRef, useState} from 'react'
import {Form, message, Tooltip} from 'antd'
import {CheckOutlined, CloseOutlined} from "@ant-design/icons";

export interface EditableFormProps<T> {
  value: T
  placeholder?: React.ReactNode
  onChange?: (value: T) => void
  editable?: boolean
  border?: boolean
  valuePropName?: string
  rules?:any[],
  getValueFromEvent?: (...args: any[]) => T // used by Form.Item to control the input component
  renderDisplay?: (value: T) => React.ReactNode
  children?: React.ReactElement // has to be a ant design form compatible input component
}
export function EditableForm <T>({ value, rules, onChange, renderDisplay, valuePropName, getValueFromEvent, placeholder, editable = true, border = true, children } : EditableFormProps<T>) {
  const context = useContext(EditableInputContext)
  const [editing, setEditing] = useState(false)
  const ref = useRef<any>()
  const childrenWithRef = children ? useMemo(() => React.cloneElement(children, {ref}), [children]) : null
  useEffect(() => {
    if (editing) {
      ref.current?.focus()
    }
    return () => {
      if (editing) {
        context.finishEditing()
      }
    }
  }, [editing])
  const [form] = Form.useForm()
  const start = () => {
    if (!editable) {
      message.warn('不可编辑')
    } else if (context.editing) {
      message.warn('请先完成输入')
    } else {
      context.startEditing()
      setEditing(true)
      form.setFieldsValue({ value })
    }
  }
  const confirm = () => {
    let value = form.getFieldValue('value');
    context.finishEditing()
    setEditing(false)
    onChange?.(value)
    form.setFieldsValue({ value })
  }
  const cancel = () => {
    context.finishEditing()
    setEditing(false)
  }
  const confirmOnEnterKey: React.KeyboardEventHandler = ({ key }) => {
    if (key === 'Enter') {
      confirm()
    }
  }
  if (editing) {
    return (
      <Form className={styles.form} form={form} onKeyDown={confirmOnEnterKey}>
        <Form.Item
          noStyle={true}
          name="value"
          valuePropName={valuePropName}
          getValueFromEvent={getValueFromEvent}
          rules={rules||[]}
        >
          {childrenWithRef}
        </Form.Item>
        <CheckOutlined className={`iconfont ${styles.confirm}`} onClick={confirm} />
        <CloseOutlined className={`iconfont ${styles.cancel}`} onClick={cancel} />
      </Form>
    )
  } else {
    return (
      <Tooltip title={editable ? '点击编辑' : '不可编辑'} placement="bottomLeft">
        <div className={`${styles.value} ${!editable ? styles.noEdit : ''} ${border ? styles.showBorder : ''}`} onClick={start}>
          {value === undefined
            ? <div className={styles.placeholder}>{placeholder ?? (editable ? '点击编辑' : '-')}</div>
            : renderDisplay?.(value) ?? (value || <div className={styles.placeholder}>{placeholder ?? (editable ? '点击编辑' : '-')}</div>)}
        </div>
      </Tooltip>
    )
  }
}

interface EditableInputContext {
  editing: boolean
  startEditing: () => void
  finishEditing: () => void
}
const EditableInputContext = React.createContext<EditableInputContext>({
  editing: false,
  startEditing: () => {},
  finishEditing: () => {}
})
// EditableInput instances inside the same provider will be mutually exclusive - only one can be in the editing state
export const EditableInputContextProvider: React.FC = ({ children }) => {
  const [editing, setEditing] = useState(false)
  const value: EditableInputContext = useMemo(() => ({
    editing,
    startEditing: () => setEditing(true),
    finishEditing: () => setEditing(false)
  }), [editing])
  return (
    <EditableInputContext.Provider value={value}>
      {children}
    </EditableInputContext.Provider>
  )
}
